#include "MRenderQueue.h"
#include "3DEDefine.h"
#include "MRenderQueueGroup.h"
#include "MRenderable.h"

CMRenderQueue::CMRenderQueue( void )
{
	// set default queue
	m_eDefaultQueueGroup = RQ_GROUPID_MAIN;
	CMRenderQueueGroup* pQueueGroup = new CMRenderQueueGroup( this , RQ_GROUPID_MAIN );

	m_pRenderQueueGroups = new RenderQueueGroupNode();

	m_pRenderQueueGroups->eRenderQueueID = RQ_GROUPID_MAIN;
	m_pRenderQueueGroups->pRenderQueueGroup = pQueueGroup;

	m_pDefaultRenderQueueGroup = m_pRenderQueueGroups;
	m_uiDefaultRenderablePriority = RENDERABLE_DEFAULT_PRIORITY;

	m_countAddRenderable = 0;
}

CMRenderQueue::~CMRenderQueue( void )
{
	RenderQueueGroupNode* pCurNode = m_pRenderQueueGroups;

	while ( pCurNode )
	{
		RenderQueueGroupNode* pDelete = pCurNode;
		pCurNode = pCurNode->pNext;

		delete pDelete->pRenderQueueGroup;
		pDelete->pRenderQueueGroup = NULL;
		pDelete->eRenderQueueID = RQ_GROUPID_UNDEFINED;
		pDelete->pPrev = NULL;
		pDelete->pNext = NULL;

		delete pDelete;			
	}

	m_countAddRenderable = 0;
}



/*! CMRenderQueue::Clear
* @param    void
* @return   void
* @see
*/

void CMRenderQueue::Clear(void)
{
	RenderQueueGroupNode* pCurNode = m_pRenderQueueGroups;

	while ( pCurNode )
	{
		pCurNode->pRenderQueueGroup->Clear();

		pCurNode = pCurNode->pNext;
	}

	m_countAddRenderable = 0;
}



/*! CMRenderQueue::AddRenderable
* @param    pRenderableObj
* @return   void
* @see
*/

void CMRenderQueue::AddRenderable(CMRenderable* pRenderableObj)
{
	AddRenderable( pRenderableObj , m_eDefaultQueueGroup , m_uiDefaultRenderablePriority );
}



/*! CMRenderQueue::AddRenderable
* @param    
* @param    eGroupID
* @return   void
* @see
*/

void CMRenderQueue::AddRenderable(CMRenderable* pRenderableObj , RenderQueueGroupID eGroupID)
{
	m_countAddRenderable +=1;
	AddRenderable( pRenderableObj , eGroupID , m_uiDefaultRenderablePriority );
}


/*! CMRenderQueue::AddRenderable
* @param    
* @param    
* @param    uiPriority
* @return   void
* @see
*/

void CMRenderQueue::AddRenderable(CMRenderable* pRenderableObj , RenderQueueGroupID eGroupID , unsigned int uiPriority)
{
	if ( m_pDefaultRenderQueueGroup->eRenderQueueID == eGroupID )
	{
		m_pDefaultRenderQueueGroup->pRenderQueueGroup->AddRenderable( pRenderableObj , pRenderableObj->GetTechnique() , uiPriority );
	}
	else
	{
		// Find group
		CMRenderQueueGroup* pGroup = GetQueueGroup( eGroupID );
		pGroup->AddRenderable( pRenderableObj , pRenderableObj->GetTechnique() , uiPriority );
	}
}



/*! CMRenderQueue::GetQueueGroup
* @param    eGroupID
* @return   CMRenderQueueGroup*
* @see
*/

CMRenderQueueGroup* CMRenderQueue::GetQueueGroup(RenderQueueGroupID eGroupID)
{
	//		__CriticalSection.Lock();

	RenderQueueGroupNode* pCurNode = m_pRenderQueueGroups;
	RenderQueueGroupNode* pPrevNode = NULL;

	while ( pCurNode )
	{
		if ( pCurNode->eRenderQueueID == eGroupID )
		{
			return pCurNode->pRenderQueueGroup;
		}

		pCurNode = pCurNode->pNext;
	}

	RenderQueueGroupNode* pNewNode  = new RenderQueueGroupNode();
	CMRenderQueueGroup* pQueueGroup = new CMRenderQueueGroup( this , eGroupID );

	pNewNode->eRenderQueueID = eGroupID;
	pNewNode->pRenderQueueGroup = pQueueGroup;

	pCurNode = m_pRenderQueueGroups;

	if ( pCurNode->eRenderQueueID > pNewNode->eRenderQueueID )
	{
		pNewNode->pNext = pCurNode;
		pCurNode->pPrev = pNewNode;

		m_pRenderQueueGroups = pNewNode;
	}
	else
	{
		while ( pCurNode )
		{
			if ( pCurNode->eRenderQueueID > pNewNode->eRenderQueueID )
			{
				RenderQueueGroupNode* pOrgPrev = pCurNode->pPrev;

				pNewNode->pPrev = pCurNode->pPrev;
				pCurNode->pPrev = pNewNode;

				pNewNode->pNext = pCurNode;
				pOrgPrev->pNext = pNewNode;

				return pNewNode->pRenderQueueGroup;
			}

			pPrevNode = pCurNode;
			pCurNode = pCurNode->pNext;
		}

		if ( pCurNode == NULL )
		{
			pPrevNode->pNext = pNewNode;
			pNewNode->pPrev = pPrevNode;
		}

	}

	return pNewNode->pRenderQueueGroup;
}


/*! CMRenderQueue::GetQueueGroups
* @param    void
* @return   CMRenderQueue::RenderQueueGroupNode*
* @see
*/

CMRenderQueue::RenderQueueGroupNode* CMRenderQueue::GetQueueGroups(void)
{	return m_pRenderQueueGroups;
}